#pragma once
#ifndef __HWINOBJECT_H__
#define __HWINOBJECT_H__

#include "hwindef.h"
#include "hwinlog.h"
#include "hwinobjimpl.h"

namespace harlinn
{
    namespace windows
    {

        class ComObject;
        class Object : public std::enable_shared_from_this<Object>
        {
            friend class ComObject;
            ComObject* comObject;
        public:
            HWIN_EXPORT Object();
            HWIN_EXPORT virtual ~Object();



            HWIN_EXPORT virtual HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, void **ppvObject );
            HWIN_EXPORT Object& Initialize();




            HWIN_EXPORT Object& AddInterface(const Guid& riid, Unknown unknown);
            HWIN_EXPORT Object& RemoveInterface(const Guid& riid);
            HWIN_EXPORT Unknown FindInterface(const Guid& riid) const;

            template<typename T> 
            std::shared_ptr<const T> As() const
            {
                HWIN_TRACE();
                return std::dynamic_pointer_cast<const T,const Object>(shared_from_this());
            }

            template<typename T> 
            std::shared_ptr<T> As()
            {
                HWIN_TRACE();
                return std::dynamic_pointer_cast<T,Object>(shared_from_this());
            }

            template<typename T> 
            bool Is() const
            {
                HWIN_TRACE();
                auto downcasted = As<T>();
                if(downcasted)
                {
                    return true;
                }
                return false;
            }

            HWIN_EXPORT virtual Object& Assign(const Object& source);
            HWIN_EXPORT virtual String GetNamePath() const;
        protected:
            HWIN_EXPORT virtual std::shared_ptr<Object> GetOwner() const;
            HWIN_EXPORT virtual const Object& AssignTo(Object& destination) const;
            HWIN_EXPORT virtual ComObject* CreateComObject() const;
        };


        template< typename T >
        std::shared_ptr<T> make_object( )
        {
            HWIN_TRACE();
            auto result = std::make_shared<T>();
            result->Initialize( );
            return result;
        }


        template< typename T, typename A >
        std::shared_ptr<T> make_object(const A& argument)
        {
            HWIN_TRACE();
            auto result = std::make_shared<T>(argument);
            result->Initialize( );
            return result;
        }

        template< typename T, typename A1, typename A2 >
        std::shared_ptr<T> make_object(const A1& argument1, const A2& argument2)
        {
            HWIN_TRACE();
            auto result = std::make_shared<T>(argument1,argument2);
            result->Initialize( );
            return result;
        }

        template< typename T, typename A1, typename A2, typename A3 >
        std::shared_ptr<T> make_object(const A1& argument1, const A2& argument2, const A3& argument3)
        {
            HWIN_TRACE();
            auto result = std::make_shared<T>(argument1,argument2,argument3);
            result->Initialize( );
            return result;
        }

        template< typename T, typename A1, typename A2, typename A3, typename A4 >
        std::shared_ptr<T> make_object(const A1& argument1, const A2& argument2, const A3& argument3, const A4& argument4)
        {
            HWIN_TRACE();
            auto result = std::make_shared<T>(argument1,argument2,argument3, argument4);
            result->Initialize( );
            return result;
        }

        template< typename T, typename A1, typename A2, typename A3, typename A4, typename A5 >
        std::shared_ptr<T> make_object(const A1& argument1, const A2& argument2, const A3& argument3, const A4& argument4, const A5& argument5)
        {
            HWIN_TRACE();
            auto result = std::make_shared<T>(argument1,argument2,argument3, argument4,argument5);
            result->Initialize( );
            return result;
        }


        




    };
};


#endif //__HWINOBJECT_H__